/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package prueba;

/**
 *
 * @author Hazziel
 */
import java.awt.Color;
import java.awt.Dimension;

import java.awt.Rectangle;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.io.BufferedReader;
import java.io.BufferedWriter;

import java.io.FileReader;
import java.io.FileWriter;

import java.util.LinkedList;

import java.util.concurrent.Semaphore;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class MainFrame extends JFrame implements Runnable {

  private JLabel lblPuente = new JLabel();

  private LinkedList<Thread> mColaNorte = new LinkedList<Thread>();
  private LinkedList<Thread> mColaSur = new LinkedList<Thread>();
  private LinkedList<Thread> mPuente = new LinkedList<Thread>();

  private int mContadorDeCarrosNorte = 1;

  private int mContadorDeCarrosSur = 1;


  private LinkedList<Thread> mProc = new LinkedList<Thread>();

  private int mCarrosNortePorMinuto = 10;

  private int mCarrosSurPorMinuto = 20;

  private long mMillisEntreCarrosEste = 0;

  private long mMillisEntreCarrosOeste = 0;

  private long mMillisDesdeElUltimoCarroNorte = 0;

  private long mMillisDesdeElUltimoCarroSur = 0;

  private int mTiempoEnPuenteNorte = 10;

  private int mTiempoEnPuenteSur = 15;

  private LinkedList<Evento> mEventos = new LinkedList<Evento>();

  private Semaphore mSemaforoEventos = new Semaphore(1);

  private Thread mGenerador = new Thread(this);
  private JTextArea lblColaNorte = new JTextArea();
  private JTextArea lblColaSur = new JTextArea();
  private JSpinner jSpinner1 = new JSpinner();
  private JSpinner jSpinner2 = new JSpinner();
  private JSpinner jSpinner3 = new JSpinner();
  private JSpinner jSpinner4 = new JSpinner();
  private JLabel jLabel1 = new JLabel();
  private JLabel jLabel2 = new JLabel();
  private JLabel jLabel3 = new JLabel();
  private JLabel jLabel4 = new JLabel();
  private JMenuBar jMenuBar1 = new JMenuBar();
  private JMenu jMenu1 = new JMenu();
  private JMenuItem jMenuItem1 = new JMenuItem();
  private JScrollPane jScrollPane1 = new JScrollPane();
  private JTextArea jTextArea1 = new JTextArea();

  public void updateLabels() {

    StringBuilder b = new StringBuilder();

    for (int i = 0; i < mColaNorte.size(); i++) {

      Thread actual = mColaNorte.get(i);
      b.append(actual.toString());

      b.append("\n");

    }

    this.lblColaNorte.setText(b.toString());

    b = new StringBuilder();

    for (int i = 0; i < mColaSur.size(); i++) {

      Thread actual = mColaSur.get(i);
      b.append(actual.toString());

      b.append("\n");

    }

    this.lblColaSur.setText(b.toString());

    b = new StringBuilder();

    for (int i = 0; i < mPuente.size(); i++) {

      Thread actual = mPuente.get(i);
      b.append(actual.toString());
      if (i < mPuente.size() - 1) {
        b.append(" , ");
      }

    }

    this.lblPuente.setText(b.toString());

  }

  public void dePuenteALimbo(Thread pCarro) {

    synchronized (mPuente) {

      mPuente.remove(pCarro);

      mProc.remove(pCarro);

      updateLabels();

    }


  }

  public void deNorteAPuente(Thread pCarro) {

    synchronized (mColaNorte) {

      mColaNorte.remove(pCarro);

      synchronized (mPuente) {

        mPuente.addFirst(pCarro);

        Evento temp = new Evento();

        temp.setSentido("Norte");

        temp.setTamañoDeLaColaEste(mColaNorte.size());

        synchronized (mColaSur) {

          temp.setTamañoDeLaColaOeste(mColaSur.size());

        }

        try {

          this.mSemaforoEventos.acquire();
          mEventos.add(temp);
          this.mSemaforoEventos.release();

        } catch (Exception ex) {
          ex.printStackTrace();
        } finally {
        }

        updateLabels();

      }

    }

  }

  public void deSurAPuente(Thread pCarro) {

    synchronized (mColaSur) {

      mColaSur.remove(pCarro);

      synchronized (mPuente) {

        mPuente.addLast(pCarro);

        Evento temp = new Evento();

        temp.setSentido("Sur");

        temp.setTamañoDeLaColaOeste(mColaSur.size());

        synchronized (mColaNorte) {

          temp.setTamañoDeLaColaEste(mColaNorte.size());

        }

        try {

          this.mSemaforoEventos.acquire();
          mEventos.add(temp);
          this.mSemaforoEventos.release();

        } catch (Exception ex) {
          ex.printStackTrace();
        } finally {
        }


        updateLabels();

      }

    }

  }

  public void addColaNorte(Thread pCarro) {

    synchronized (mColaNorte) {

      mColaNorte.addLast(pCarro);

      updateLabels();

    }

  }

  public void addColaSur(Thread pCarro) {

    synchronized (mColaSur) {

      mColaSur.addLast(pCarro);

      updateLabels();

    }

  }

  public MainFrame() {
    super("Programacion Concurrente y Paralela");
    try {
      
      BufferedWriter writer = new BufferedWriter( new FileWriter("log.txt",false) );
      
      writer.write("Inicio:\n\n");
      
      writer.close();
      
    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
    }

    try {
      jbInit();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception {
    this.getContentPane().setLayout(null);
    this.setSize(new Dimension(513, 522));
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setResizable(false);
    this.setJMenuBar(jMenuBar1);
    lblPuente.setBounds(new Rectangle(85, 70, 330, 90));
    lblPuente.setBackground(Color.CYAN);
    lblPuente.setOpaque(true);
    lblPuente.setHorizontalAlignment(SwingConstants.CENTER);
    lblPuente.setHorizontalTextPosition(SwingConstants.CENTER);
    lblColaNorte.setBounds(new Rectangle(5, 20, 75, 205));
    lblColaSur.setBounds(new Rectangle(420, 20, 75, 205));

    lblColaNorte.setBorder(BorderFactory.createBevelBorder(1));
    lblColaSur.setBorder(BorderFactory.createBevelBorder(1));
    lblColaNorte.setBackground(Color.GREEN);
    lblColaSur.setBackground(Color.GREEN);
    
    lblPuente.setBorder(BorderFactory.createBevelBorder(1));
    
    
    jSpinner1.setBounds(new Rectangle(455, 0, 40, 25));

    jSpinner1.addChangeListener(new ChangeListener() {
        public void stateChanged(ChangeEvent e) {
          jSpinner1_stateChanged(e);
        }
      });
    Integer value = new Integer(20);
    Integer min = new Integer(0);
    Integer max = new Integer(60);
    Integer step = new Integer(1);
    SpinnerNumberModel model = new SpinnerNumberModel(value, min, max, step);

    jSpinner1.setModel(model);

    value = new Integer(15);
    min = new Integer(1);
    max = new Integer(100);
    step = new Integer(1);
    model = new SpinnerNumberModel(value, min, max, step);

    jSpinner2.setBounds(new Rectangle(455, 35, 40, 25));

    jSpinner2.addChangeListener(new ChangeListener() {
        public void stateChanged(ChangeEvent e) {
          jSpinner2_stateChanged(e);
        }
      });
    jSpinner2.setModel(model);

    jSpinner3.setBounds(new Rectangle(150, 40, 40, 25));
    jSpinner3.addChangeListener(new ChangeListener() {
        public void stateChanged(ChangeEvent e) {
          jSpinner3_stateChanged(e);
        }
      });
    value = new Integer(10);
    min = new Integer(0);
    max = new Integer(60);
    step = new Integer(1);
    model = new SpinnerNumberModel(value, min, max, step);
    jSpinner4.setModel(model);

    jSpinner4.setBounds(new Rectangle(150, 5, 40, 25));
    jSpinner4.addChangeListener(new ChangeListener() {
        public void stateChanged(ChangeEvent e) {
          jSpinner4_stateChanged(e);
        }
      });
    jLabel1.setText("Carros Sur Por  Minuto");
    jLabel1.setBounds(new Rectangle(300, 5, 145, 20));
    jLabel2.setText("Carros Norte Por  Minuto");
    jLabel2.setBounds(new Rectangle(5, 10, 145, 20));
    jLabel3.setText("Tiempo En El Puente");
    jLabel3.setBounds(new Rectangle(300, 40, 145, 20));
    jLabel4.setText("Tiempo En El Puente");
    jLabel4.setBounds(new Rectangle(5, 45, 145, 20));
    jMenu1.setText("Archivo");
    jMenuItem1.setText("Escribir");
    jMenuItem1.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          jMenuItem1_actionPerformed(e);
        }
      });
    jScrollPane1.setBounds(new Rectangle(5, 240, 490, 220));
    jScrollPane1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
    jScrollPane1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    value = new Integer(10);
    min = new Integer(1);
    max = new Integer(100);
    step = new Integer(1);
    model = new SpinnerNumberModel(value, min, max, step);
    jSpinner3.setModel(model);

    jScrollPane1.getViewport().add(jTextArea1, null);
    this.getContentPane().add(jScrollPane1, null);
    //this.getContentPane().add(jLabel4, null);
    //this.getContentPane().add(jLabel3, null);
    //this.getContentPane().add(jLabel2, null);
    //this.getContentPane().add(jLabel1, null);
    //this.getContentPane().add(jSpinner4, null);
    //this.getContentPane().add(jSpinner3, null);
    //this.getContentPane().add(jSpinner2, null);
    //this.getContentPane().add(jSpinner1, null);


    this.getContentPane().add(lblColaSur, null);
    this.getContentPane().add(lblColaNorte, null);
    this.getContentPane().add(lblPuente, null);
    jMenu1.add(jMenuItem1);
    jMenuBar1.add(jMenu1);
    mGenerador.start();

  }

  private void jButton2_actionPerformed(ActionEvent e) {

    /*CarroEste temp = new CarroEste();
    temp.setNombre( "Este[" + this.mContadorDeCarros + "]" );
    mContadorDeCarros++;
    temp.setFrame(this);
    temp.start();*/

  }

  public void run() {

    try {

      long millisPorMinuto = 60 * 1000;

      this.mMillisEntreCarrosEste =
          (long)((float)millisPorMinuto / (float)this.mCarrosNortePorMinuto);

      this.mMillisEntreCarrosOeste =
          (long)((float)millisPorMinuto / (float)this.mCarrosSurPorMinuto);

      int seg = 0;
      
      while (true) {

        if( seg == 2 ) {
          
          seg = 0;
          
          try {
            
            BufferedReader reader = new BufferedReader( new FileReader("log.txt") );
            
            StringBuilder b = new StringBuilder();
            
            String line = "";
            
            while ( (line = reader.readLine()) != null)            
            {
              b.append(line + "\n");
            }
                
            this.jTextArea1.setText( b.toString() );
            
          } catch (Exception ex) {
            ex.printStackTrace();
          } finally {
          }


        }
        
        if (this.mMillisDesdeElUltimoCarroNorte > this.mMillisEntreCarrosEste &&
            this.mMillisEntreCarrosEste > 0) {

          CarroNorte temp = new CarroNorte();
          temp.setNombre("N[" + this.mContadorDeCarrosNorte + "]");
          mContadorDeCarrosNorte++;
          temp.setFrame(this);
          temp.setTiempoParaCruzar(this.mTiempoEnPuenteNorte);
          temp.start();

          this.mMillisDesdeElUltimoCarroNorte = 0;
        }

        if (this.mMillisDesdeElUltimoCarroSur >
            this.mMillisEntreCarrosOeste && this.mMillisEntreCarrosOeste > 0) {

          CarroSur temp = new CarroSur();
          temp.setNombre("S[" + this.mContadorDeCarrosSur + "]");
          mContadorDeCarrosSur++;
          temp.setFrame(this);
          temp.setTiempoParaCruzar(this.mTiempoEnPuenteSur);
          temp.start();

          this.mMillisDesdeElUltimoCarroSur = 0;
        }
        
        Thread.sleep(500);

        this.mMillisDesdeElUltimoCarroSur += 500;

        this.mMillisDesdeElUltimoCarroNorte += 500;
        
        seg ++;

      }


    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
    }


  }

  private void jSpinner2_stateChanged(ChangeEvent e) {

    this.mTiempoEnPuenteSur = (Integer)jSpinner2.getValue();

  }

  private void jSpinner3_stateChanged(ChangeEvent e) {

    this.mTiempoEnPuenteNorte = (Integer)jSpinner3.getValue();

  }

  private void jSpinner4_stateChanged(ChangeEvent e) {

    long millisPorMinuto = 60 * 1000;

    mCarrosNortePorMinuto = (Integer)jSpinner4.getValue();

    if (mCarrosNortePorMinuto == 0) {
      this.mMillisEntreCarrosEste = 0;
    } else {

      this.mMillisEntreCarrosEste =
          (long)((float)millisPorMinuto / (float)this.mCarrosNortePorMinuto);

    }

  }

  private void jSpinner1_stateChanged(ChangeEvent e) {

    long millisPorMinuto = 60 * 1000;

    mCarrosSurPorMinuto = (Integer)jSpinner1.getValue();

    if (mCarrosSurPorMinuto == 0) {
      mMillisEntreCarrosOeste = 0;
    } else {
      this.mMillisEntreCarrosOeste =
          (long)((float)millisPorMinuto / (float)this.mCarrosSurPorMinuto);
    }

  }

  public void setEventos(LinkedList<Evento> mEventos) {
    this.mEventos = mEventos;
  }

  public LinkedList<Evento> getEventos() {
    return mEventos;
  }

  public synchronized void setSemaforoEventos(Semaphore mSemaforoEventos) {
    this.mSemaforoEventos = mSemaforoEventos;
  }

  public synchronized Semaphore getSemaforoEventos() {
    return mSemaforoEventos;
  }

  private void jMenuItem1_actionPerformed(ActionEvent e) {
    //escribir
    
    try {
      
      this.mSemaforoEventos.acquire();
      
      StringBuilder b = new StringBuilder();
      
      for( int i = 0; i < mEventos.size(); i++ ) {
        
        jTextArea1.setText("");
        b.append( mEventos.get(i).toString());
        b.append("\n");
        System.out.println(b.append( mEventos.get(i).toString()));
      }
      
      /*for( int i = 0; i < mEventos.size(); i++ ) {
        System.out.println(b.append( mEventos.get(i).toString()));
      }*/
      
      mEventos.clear();
      
      BufferedWriter writer = new BufferedWriter( new FileWriter("log.txt",true) );
      writer.write( b.toString() ) ;
      
      writer.close() ;
      
      this.mSemaforoEventos.release();
      
    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
    }


  }
}
